#pragma once

#include <iostream>
#include <ostream>
#include <string>
#include <unordered_map>

#include "arithmetic.h"
#include "arm.h"
#include "types.h"

namespace Arm {
    struct Register : public Printable {
        enum {
            fp = 11,
            ip = 12,
            sp = 13,
            lr = 14,
            pc = 15,
        };

        Type::Basic type;
        int id;

        Register(int id);
        Register(Type::Basic type, int id);
        void GenAsm(std::ostream& os) const override;
    };

    struct MemObj : public Printable {};

    struct GlobalVar : public MemObj {
        std::string name;
        int size;
        std::unordered_map<int, int>* init = nullptr;

        void GenAsm(std::ostream& os) const override;
    };

    struct ImmOffset : public MemObj {
        Register base;
        int offset;

        ImmOffset(Register base, int offset);
        void GenAsm(std::ostream& os) const override;
    };

    struct RegOffset : public MemObj {
        Register base;
        Register offset;
        int lshift;

        RegOffset(Register base, Register offset, int lshift);
        void GenAsm(std::ostream& os) const override;
    };

    struct Immediate : public MemObj {
        ArithValue value;

        void GenAsm(std::ostream& os) const override;
    };
}  // namespace Arm
